package org.naivecoders.ai.types;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * Each bowl contains immutable ordered set of other bowls. The set can be empty
 * in which case the bowl is treated as a marble.
 * 
 */
public class Bowl {
	private final List<Bowl> contents = new ArrayList<Bowl>();

	public Bowl(Bowl... kids) {
		contents.addAll(Arrays.asList(kids));
	}

	private static Bowl parseBrackets(char[] c, int[] start) {
		final List<Bowl> kids = new ArrayList<Bowl>();

		for (int i = start[0]; i < c.length; i++) {
			if ('[' == c[i]) {
				start[0] = i+1;
				kids.add(parseBrackets(c, start));
				i = start[0];
			} else if (']' == c[i]) {
				start[0] = i;
				return new Bowl(kids.toArray(new Bowl[kids.size()]));
			}
		}
		throw new IllegalArgumentException();

	}

	public static Bowl parseBracketNotation(String st) {
		final char[] c = new char[st.length()];
		st.getChars(0, c.length, c, 0);
		return parseBrackets(c, new int[] { 1 });
	}

	public MaybeBowl getHead() {
		if (contents.isEmpty()) {
			return MaybeBowl.NOTHING;
		}
		return MaybeBowl.newBowl(contents.get(0));
	}

	public MaybeBowl getTail() {
		if (contents.isEmpty()) {
			return MaybeBowl.NOTHING;
		}
		final Bowl[] kids = new Bowl[contents.size() - 1];
		final Iterator<Bowl> ik = contents.iterator();
		ik.next();

		for (int i = 0; i < kids.length; i++) {
			kids[i] = ik.next();
		}
		return MaybeBowl.newBowl(contents.get(0));
	}

	public Bowl append(Bowl head) {
		final List<Bowl> b = new ArrayList<Bowl>();
		b.add(head);
		b.addAll(contents);
		return new Bowl(b.toArray(new Bowl[b.size()]));
	}

	public int getSize() {
		return contents.size();
	}

	private void appendBowlDescription(StringBuilder sb, Bowl b) {
		sb.append("[");
		for (Bowl bb : b.contents) {
			appendBowlDescription(sb, bb);
		}
		sb.append("]");
	}

	@Override
	public String toString() {
		final StringBuilder sb = new StringBuilder();
		appendBowlDescription(sb, this);
		return sb.toString();
	}
}
